package model.dominio.listasSimples;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Clase que se encarga de crear una lista simple 
 * @author Gustavo Canul, Noe Cob, Arandi López
 */
public class ListaSimple extends Lista {
    

    /**
     * Metodo que inserta el nodo al principio de la lista 
     * @param frecuencia
     * @param letra
     */
    @Override
    public void insertarFrente(Object frecuencia,char letra) {

        if (esVacio()) {
            try {
                this.primerNodo = this.ultimoNodo = new NodosLista(frecuencia, letra);
            } catch (IOException ex) {
                Logger.getLogger(ListaSimple.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            try {
                this.primerNodo = new NodosLista(frecuencia, this.primerNodo, letra);
            } catch (IOException ex) {
                Logger.getLogger(ListaSimple.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Metodo que inserta el nodo al final de la lista 
     * @param frecuencia
     * @param letra
     */
    @Override
    public void insertarFinal(Object frecuencia,char letra) {

        if (esVacio()) {
            try {
                this.primerNodo = this.ultimoNodo = new NodosLista(frecuencia, letra);
            } catch (IOException ex) {
                Logger.getLogger(ListaSimple.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            try {
                this.ultimoNodo.establecerSiguiente(new NodosLista(frecuencia, letra));
                this.ultimoNodo = this.ultimoNodo.obtenerSiguiente();
            } catch (IOException ex) {
                Logger.getLogger(ListaSimple.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

 
    /**
     * Metodo que inserta los nodos en la lista en orden de menor a mayor
     * @param frecuencia
     * @param letra
     * @throws IOException
     */
    @Override
    public void insertarOrden(Object frecuencia , char letra) throws IOException {
        if (esVacio()) {
            this.primerNodo = ultimoNodo = new NodosLista(frecuencia, letra);
        } else {
            if (primerNodo == ultimoNodo) {
                if ((Integer) frecuencia < (Integer) primerNodo.obtenerDato()) {
                    insertarFrente(frecuencia,letra);
                } else {
                    insertarFinal(frecuencia,letra);
                }
            } else {
                NodosLista current = this.primerNodo;
                NodosLista prev = null;

                while (current != null && (Integer) frecuencia > (Integer) current.obtenerDato()) {
                    prev = current;
                    current = current.obtenerSiguiente();
                }

                if (prev == null) {
                    insertarFrente(frecuencia, letra);
                } else {
                    if (prev == ultimoNodo) {
                        insertarFinal(frecuencia, letra);
                    } else {
                        NodosLista nuevo = new NodosLista(frecuencia, letra);
                        prev.establecerSiguiente(nuevo);
                        nuevo.establecerSiguiente(current);
                    }
                }
            }
        }
    }
    
    
    /**
     * Metodo que  remueve el nodo del frente de la lista 
     * @return removedItem
     * @throws ExcepcionListaVacia
     */
    @Override
    public Object removerFrente() throws ExcepcionListaVacia {
        if (esVacio()) {
            throw new ExcepcionListaVacia();
        }
        Object removedItem = this.primerNodo.obtenerDato();
        if (primerNodo == ultimoNodo) {
            this.primerNodo = this.ultimoNodo = null;
        } else {
            this.primerNodo = primerNodo.obtenerSiguiente();
        }
        return removedItem;
    }

    /**
     * Metodo que remueve el nodo al final de la lista 
     * @return removedItem
     * @throws ExcepcionListaVacia
     */
    @Override
    public Object removerFinal() throws ExcepcionListaVacia {
        if (esVacio()) {
            throw new ExcepcionListaVacia();
        }

        Object removedItem = ultimoNodo.obtenerDato();

        if (primerNodo == ultimoNodo) {
            this.primerNodo = this.ultimoNodo = null;
        } else {
            NodosLista current = this.primerNodo;

            while (current.obtenerSiguiente() != ultimoNodo) {
                current = current.obtenerSiguiente();
            }

            current.establecerSiguiente(null);
        }

        return removedItem;
    }

    /**
     * Metodo que remueve el nodo de cualquier parte de la lista 
     * @param frecuencia
     * @param letra
     * @return
     * @throws ExcepcionListaVacia
     */
    @Override
    public Object removerObjeto(Object frecuencia,char letra) throws ExcepcionListaVacia {
        if (esVacio()) {
            throw new ExcepcionListaVacia();
        }

        if ((Integer) this.primerNodo.obtenerDato() == (Integer) frecuencia) {
            removerFrente();
        }

        NodosLista current = this.primerNodo;
        NodosLista prev = current;

        while (current != null) {

            if ((Integer) current.obtenerDato() == (Integer) frecuencia) {
                prev.establecerSiguiente(current.obtenerSiguiente());
            } else {
                prev = current;
            }

            current = current.obtenerSiguiente();
        }
        return frecuencia;
    }
    

}
